/*
 * @Description: 模拟HTTP请求
 * @Author: YangHeng
 * @Date: 2021-08-12 14:10:24
 * @FilePath: \web_server_app\utils\mock-http.js
 */

const http = require('http');
const { isString } = require('core-util-is');
const querystring = require('querystring');
const Readable = require('stream').Readable;
const IncomingMessage = http.IncomingMessage;
const ServerResponse = http.ServerResponse;

/**
 * default mock args
 */
const defaultArgs = {
  method: 'GET',
  httpVersion: '1.1'
};

/**
 * @description: 模拟HTTP请求
 * @param {*} reqArgs 请求体 包含 req, res和其他需要挂在在请求体上的参数
 * @param {*} app koa 实例 用于转发请求到koa的回调
 * @return {*} 
 */
module.exports = function (reqArgs, app) {
  if (isString(reqArgs)) {
    if (reqArgs[0] === '{') {
      reqArgs = JSON.parse(reqArgs);
    } else if (/^\w+=/.test(reqArgs)) {
      reqArgs = querystring.parse(reqArgs);
    } else {
      reqArgs = { url: reqArgs };
    }
  }

  // 合成request
  let req = null;
  if (reqArgs.req) {
    req = Object.assign({}, reqArgs.req);
    delete reqArgs.req;
  } else {
    req = new IncomingMessage(new Readable());
  }

  // 合成response
  let res = null;
  if (reqArgs.res) {
    res = reqArgs.res;
    delete reqArgs.res;
  } else {
    res = new ServerResponse(req);
  }

  // 重写请求end方法
  if (reqArgs.exitOnEnd) {
    delete reqArgs.exitOnEnd;
    res.end = msg => {
      process.exit();
    };
  }

  // 合并请求参数
  const args = Object.assign({}, defaultArgs, reqArgs);
  for (const name in args) {
    req[name] = args[name];
  }

  // 发起请求
  if (!app || !app.callback) return { req, res };
  const fn = app.callback();
  return fn(req, res)
}